#include "tools/log.hpp"
#include "tools/timer.hpp"
#include <mutex>
#include <string>
#include <unordered_map>

namespace toolsLib
{

std::unordered_map<std::string, std::chrono::time_point<std::chrono::high_resolution_clock>>
    Timer::startTimeString;

std::unordered_map<int, std::chrono::time_point<std::chrono::high_resolution_clock>>
    Timer::startTimeInt;

std::unordered_map<std::string, std::string> Timer::startFileString;
std::unordered_map<std::string, std::string> Timer::startFuncNameString;
std::unordered_map<std::string, int> Timer::startLineString;

// 线程安全互斥锁
static std::mutex timerMutex;

Timer& Timer::getInstance()
{
    static Timer instance;
    return instance;
}

void Timer::begin(const std::string& file,
                  const std::string& funcName,
                  const int line,
                  const std::string& startMessage)
{
    templateBegin(file, funcName, line, startMessage);
}

void Timer::begin(const std::string& file,
                  const std::string& funcName,
                  const int line,
                  const int startMessage)
{
    templateBegin(file, funcName, line, startMessage);
}

void Timer::end(const std::string& file,
                const std::string& funcName,
                const int line,
                const int level,
                const std::string& endMessage)
{
    templateEnd(file, funcName, line, level, endMessage);
}

void Timer::end(const std::string& file,
                const std::string& funcName,
                const int line,
                const int level,
                const int endMessage)
{
    templateEnd(file, funcName, line, level, endMessage);
}

template <typename T>
void Timer::templateBegin(const std::string& startFile,
                          const std::string& startFuncName,
                          const int startLine,
                          const T& startMessage)
{
    std::string message;
    message = toolsLib::Logger::getInstance().to_string(startMessage);
    
    std::lock_guard<std::mutex> lock(timerMutex);
    
    auto it = startTimeString.find(message);
    if (it != startTimeString.end()) {
        return;  // 已经存在，不重复开始
    } else {
        auto time = std::chrono::high_resolution_clock::now();
        startTimeString[message] = time;
        startFileString[message] = startFile;
        startFuncNameString[message] = startFuncName;
        startLineString[message] = startLine;
    }
}

template <typename T>
void Timer::templateEnd(const std::string& endFile,
                        const std::string& endFuncName,
                        const int endLine,
                        const int level,
                        const T& endMessage)
{
    std::string message;
    message = toolsLib::Logger::getInstance().to_string(endMessage);
    
    // 保存需要的数据（在锁保护下）
    std::chrono::time_point<std::chrono::high_resolution_clock> start;
    std::string startFile;
    std::string startFuncName;
    int startLine = 0;
    bool found = false;
    
    {
        std::lock_guard<std::mutex> lock(timerMutex);
        
        auto it = startTimeString.find(message);
        if (it == startTimeString.end()) {
            return;  // 没有对应的开始时间，直接返回
        }
        
        // 保存需要的数据，因为后面会删除
        start = std::chrono::time_point_cast<std::chrono::microseconds>(it->second);
        startFile = startFileString[message];
        startFuncName = startFuncNameString[message];
        startLine = startLineString[message];
        found = true;
        
        // 删除记录
        startTimeString.erase(message);
        startFileString.erase(message);
        startFuncNameString.erase(message);
        startLineString.erase(message);
    }  // 锁在这里自动释放
    
    if (!found) {
        return;
    }
    
    auto endTime = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - start);
    long long totalSeconds = duration.count() / microsecondsInSecond;
    long long totalMinutes = totalSeconds / 60;
    long long totalHours = totalMinutes / 60;
    long long totalDays = totalHours / 24;
    int seconds = static_cast<int>(totalSeconds % 60);
    int minutes = static_cast<int>(totalMinutes % 60);
    int hours = static_cast<int>(totalHours % 24);
    int days = static_cast<int>(totalDays);
    int milliseconds = static_cast<int>((duration.count() % microsecondsInSecond) / 1000);
    int microsecondsRemainder = static_cast<int>(duration.count() % 1000);

    std::string sec = doubleToString(seconds, 2);
    std::string min = doubleToString(minutes, 2);
    std::string hou = doubleToString(hours, 2);
    std::string day = doubleToString(days, 3);
    std::string mil = doubleToString(milliseconds, 3);
    std::string mic = doubleToString(microsecondsRemainder, 3);

    std::string nowTime;
    toolsLib::Logger::getInstance().timeCurrently(nowTime);

    // 修复：移除重复的 getFileName 调用
    std::string part1 = nowTime + "[" + startFuncName + " " +
                        toolsLib::Logger::getInstance().getFileName(startFile) +
                        ":" + std::to_string(startLine) + "] ";
    std::string part2 = "Process \"" + message + "\" took [" + day + "D " + hou + "H " + min + "M " + sec +
                        "S " + mil + "m " + mic + "μ].";
    std::string part3 = " [" + endFuncName + " " +
                        toolsLib::Logger::getInstance().getFileName(endFile) + ":" +
                        std::to_string(endLine) + "]";

    toolsLib::Logger::getInstance().unpolishedLog(level, part1, part2, part3);
}

std::string Timer::doubleToString(double num, int precision)
{
    std::ostringstream os;
    os << std::setfill('0') << std::setw(precision) << num;
    return os.str();
}

}  // namespace toolsLib
